package com.hu.common.util.adm;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.alibaba.excel.metadata.CellExtra;
import com.hu.common.enums.MessageEnum;
import com.hu.common.exception.BizException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;
import java.util.Map;

/**
 * @ClassName ExcelHelper
 * @Description excel处理工具类
 * @author 355760
 **/
public class ExcelHelper {
    private static final Logger logger = LoggerFactory.getLogger(ExcelHelper.class);

    /**
     * 返回读取的数据
     *
     * @param file          上传的excel文件
     * @param sheetNo       sheet页码
     * @param headRowNumber excel表头位置
     * @return List<Map < Integer, String>>
     * @throws Exception exception
     */
    public List<Map<Integer, String>> getCellList(MultipartFile file, Integer sheetNo, Integer headRowNumber) throws Exception {
        ImportExcelListener<Map<Integer, String>> listener = new ImportExcelListener<>(headRowNumber);

        try {
            EasyExcel.read(file.getInputStream(), listener)
                    .extraRead(CellExtraTypeEnum.MERGE)
                    .sheet(sheetNo)
                    .headRowNumber(headRowNumber)
                    .doRead();
        } catch (Exception e) {
            logger.error("[read excel exception:] {}", E2s.exception2String(e));
            throw new BizException(MessageEnum.IO_EXCEPTION.getMessage());
        }

        List<CellExtra> extraMergeInfoList = listener.getExtraMergeInfoList();
        // 没有合并单元格情况，直接返回即可
        if (Assert.isEmpty(extraMergeInfoList) || extraMergeInfoList.isEmpty()) {
            return listener.getData();
        }

        return mergeCellData(listener.getData(), extraMergeInfoList, headRowNumber);
    }

    /**
     * 处理合并单元格
     *
     * @param data               解析数据
     * @param extraMergeInfoList 合并单元格信息
     * @param headRowNumber      起始行
     * @return 填充好的解析数据
     */
    private List<Map<Integer, String>> mergeCellData(List<Map<Integer, String>> data, List<CellExtra> extraMergeInfoList, Integer headRowNumber) {
        //循环所有合并单元格信息
        extraMergeInfoList.forEach(cellExtra -> {
            int firstRowIndex = cellExtra.getFirstRowIndex() - headRowNumber;
            int lastRowIndex = cellExtra.getLastRowIndex() - headRowNumber;
            int firstColumnIndex = cellExtra.getFirstColumnIndex();
            int lastColumnIndex = cellExtra.getLastColumnIndex();
            //获取初始值
            Object initValue = getInitValueFromList(firstRowIndex, firstColumnIndex, data);
            //设置值
            for (int i = firstRowIndex; i <= lastRowIndex; i++) {
                for (int j = firstColumnIndex; j <= lastColumnIndex; j++) {
                    setInitValueToList(initValue, i, j, data);
                }
            }
        });
        return data;
    }

    /**
     * 设置合并单元格的值
     *
     * @param filedValue  值
     * @param rowIndex    行
     * @param columnIndex 列
     * @param data        解析数据
     */
    private void setInitValueToList(Object filedValue, Integer rowIndex, Integer columnIndex, List<Map<Integer, String>> data) {
        if (rowIndex < data.size()) {
            Map<Integer, String> map = data.get(rowIndex);
            if (Assert.notEmpty(map)) {
                for (Map.Entry<Integer, String> entry : map.entrySet()) {
                    if (entry.getKey().equals(columnIndex) && Assert.notEmpty(filedValue)) {
                        entry.setValue(filedValue.toString());
                        break;
                    }
                }
            }
        }

    }


    /**
     * 获取合并单元格的初始值
     * rowIndex对应list的索引
     * columnIndex对应实体内的字段
     *
     * @param firstRowIndex    起始行
     * @param firstColumnIndex 起始列
     * @param data             列数据
     * @return 初始值
     */
    private Object getInitValueFromList(Integer firstRowIndex, Integer firstColumnIndex, List<Map<Integer, String>> data) {
        Object filedValue = null;
        Map<Integer, String> map = data.get(firstRowIndex);
        if (Assert.notEmpty(map)) {
            for (Map.Entry<Integer, String> entry : map.entrySet()) {
                if (entry.getKey().equals(firstColumnIndex)) {
                    filedValue = entry.getValue();
                    break;
                }
            }
        }
        return filedValue;
    }
}
